/*
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 */
package ai.individual;

import java.util.List;
//import java.util.logging.Logger;

import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ACTIVE;
//import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;

import com.l2jserver.gameserver.ai.CtrlIntention;
import com.l2jserver.gameserver.datatables.NpcTable;
import com.l2jserver.gameserver.datatables.SkillTable;
import com.l2jserver.gameserver.datatables.SpawnTable;
import com.l2jserver.gameserver.idfactory.IdFactory;
import com.l2jserver.gameserver.instancemanager.GrandBossManager;
import com.l2jserver.gameserver.model.L2Skill;
import com.l2jserver.gameserver.model.L2Spawn;
import com.l2jserver.gameserver.model.actor.L2Attackable;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2GrandBossInstance;
import com.l2jserver.gameserver.model.actor.instance.L2MinionInstance;
import com.l2jserver.gameserver.model.actor.instance.L2MonsterInstance;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.zone.type.L2BossZone;
import com.l2jserver.gameserver.network.serverpackets.MoveToPawn;
import com.l2jserver.gameserver.network.serverpackets.PlaySound;
import com.l2jserver.gameserver.network.serverpackets.SocialAction;
import com.l2jserver.gameserver.templates.StatsSet;
import com.l2jserver.gameserver.templates.chars.L2NpcTemplate;
import com.l2jserver.gameserver.util.Util;
import com.l2jserver.util.Rnd;

import javolution.util.FastList;
import ai.group_template.L2AttackableAIScript;

/**
 * Queen Ant AI
 * 
 * @author Emperorc
 * 
 */
public class QueenAnt extends L2AttackableAIScript
{	
	//protected static final Logger _log = Logger.getLogger(QueenAnt.class.getName());
	
	private static final int QUEEN = 29001;
	private static final int LARVA = 29002;
	private static final int NURSE = 29003;
	private static final int GUARD = 29004;
	private static final int ROYAL = 29005;
	private L2Npc _larva = null;
	private L2MonsterInstance _queen = null;
	private static long _lastattack = 0;
	private static List<L2Attackable> _Minions = new FastList<L2Attackable>();
	//QUEEN Status Tracking :
	private static final byte ALIVE = 0;	//Queen Ant is spawned.
	private static final byte DEAD = 1;		//Queen Ant has been killed.
	
	private static L2BossZone _Zone;
	public QueenAnt (int questId, String name, String descr)
	{
        super(questId,name,descr);
        int[] mobs = {QUEEN, LARVA, NURSE, GUARD, ROYAL};
        registerMobs(mobs);
        _Zone = GrandBossManager.getInstance().getZone(-21610,181594,-5734);

        StatsSet info = GrandBossManager.getInstance().getStatsSet(QUEEN);
        int status = GrandBossManager.getInstance().getBossStatus(QUEEN);
        if (status == DEAD)
        {
            // load the unlock date and time for queen ant from DB
            long temp = info.getLong("respawn_time") - System.currentTimeMillis();
            // if queen ant is locked until a certain time, mark it so and start the unlock timer
            // the unlock time has not yet expired.
            if (temp > 0)
                startQuestTimer("queen_unlock", temp, null, null);
            else
            {
                // the time has already expired while the server was offline. Immediately spawn queen ant.
                L2GrandBossInstance queen = (L2GrandBossInstance) addSpawn(QUEEN,-21610,181594,-5734,0,false,0);
                _queen = (L2MonsterInstance) queen;
                GrandBossManager.getInstance().setBossStatus(QUEEN,ALIVE);
                spawnBoss(queen);
            }
        }
        else
        {
            /*int loc_x = info.getInteger("loc_x");
            int loc_y = info.getInteger("loc_y");
            int loc_z = info.getInteger("loc_z");
            int heading = info.getInteger("heading");
            int hp = info.getInteger("currentHP");
            int mp = info.getInteger("currentMP");
            L2GrandBossInstance queen = (L2GrandBossInstance) addSpawn(QUEEN,loc_x,loc_y,loc_z,heading,false,0);
            queen.setCurrentHpMp(hp,mp);*/
        	L2GrandBossInstance queen = (L2GrandBossInstance) addSpawn(QUEEN,-21610,181594,-5734,0,false,0);
        	_queen = (L2MonsterInstance) queen;
        	spawnBoss(queen);
        }
	}

    public void spawnBoss(L2GrandBossInstance npc)
    {
        GrandBossManager.getInstance().addBoss(npc);
        if (Rnd.get(100) < 33)
            _Zone.movePlayersTo(-19480,187344,-5600);
        else if (Rnd.get(100) < 50)
            _Zone.movePlayersTo(-17928,180912,-5520);
        else
            _Zone.movePlayersTo(-23808,182368,-5600);
        GrandBossManager.getInstance().addBoss(npc);
        startQuestTimer("action",10000, npc, null, true);
       // startQuestTimer("check_larva_queen",60000, npc, null, true);
        npc.broadcastPacket(new PlaySound(1, "BS02_D", 1, npc.getObjectId(), npc.getX(), npc.getY(), npc.getZ()));
        _larva = addSpawn(LARVA,-21600,179482,-5846,Rnd.get(360),false,0);
        _larva.setIsRaidMinion(true);
       // L2MonsterInstance mob1 = (L2MonsterInstance) _larva;
        startQuestTimer("checklarva",30000,_larva,null, true);
        //spawnSingleMinion(NURSE,400,mob1);
        //spawnSingleMinion(NURSE,-400,mob1);
    }

	public String onAdvEvent (String event, L2Npc npc, L2PcInstance player)
	{
        if (event.equalsIgnoreCase("action") && npc != null)
        {
        	for(L2MinionInstance min : _queen.getSpawnedMinions())
			{
        		if (min.getNpcId() == ROYAL)
        			return null;
        		if (min.isCastingNow()) 
                	return null;
                if (_larva.getCurrentHp() != _larva.getMaxHp())
                {
                	if(Util.checkIfInRange(600, min, _larva, false))
                	{
                    	min.setTarget(_larva);
                        min.setIsCastingNow(true);
                        min.doCast(SkillTable.getInstance().getInfo(4024,1));
                	}
                	else
                	{ 
                		if (min.getTarget() != null)
                		{
                			if (min.getTarget() instanceof L2Character)
                			{
                				min.stopHating(((L2Character) min.getTarget()));
                				min.getAI().setIntention(AI_INTENTION_ACTIVE, null, null);
                				min.setRunning();
                			}
                		}
                		min.broadcastPacket(new MoveToPawn(min,_larva,500));
                	}
                }
                else if (npc.getCurrentHp() != npc.getMaxHp())
                {
                	if(Util.checkIfInRange(600, min, npc, false))
                	{
                		min.setTarget(npc);
                		min.setIsCastingNow(true);
                		min.doCast(SkillTable.getInstance().getInfo(4020,1));
                	}
                	else
                	{
                		if (min.getTarget() != null)
                		{
                			if (min.getTarget() instanceof L2Character)
                			{
                				min.stopHating(((L2Character) min.getTarget()));
                				min.getAI().setIntention(AI_INTENTION_ACTIVE, null, null);
                				min.setRunning();
                			}
                		}
                		min.broadcastPacket(new MoveToPawn(min,npc,500));
                	}               	
                }
			}
            if (Rnd.get(3)==0)
            {
                if (Rnd.get(2)==0)
                {
                    npc.broadcastPacket(new SocialAction(npc.getObjectId(),3));
                }
                else
                {
                    npc.broadcastPacket(new SocialAction(npc.getObjectId(),4));
                }
            }
        }
        else if (event.equalsIgnoreCase("queen_unlock"))
        {
            L2GrandBossInstance queen = (L2GrandBossInstance) addSpawn(QUEEN,-21610,181594,-5734,0,false,0);
            GrandBossManager.getInstance().setBossStatus(QUEEN,ALIVE);
            _queen = (L2MonsterInstance) queen;
            spawnBoss(queen);
        }
        else if (event.equalsIgnoreCase("spawn_royal"))
        {	
        	spawnSingleMinion(ROYAL,0,((L2MinionInstance)npc).getLeader());
        }
        else if (event.equalsIgnoreCase("spawn_nurse"))
        {
	    	spawnSingleMinion(NURSE,0,((L2MinionInstance)npc).getLeader());
        }
        //-21600,179482,-5846
        else if (event.equalsIgnoreCase("checklarva"))
        {
	    	if(!checkLarvaZone(npc,800,-21600,179482,-5846))
	    	{
	    		 if (_lastattack + 300000 < System.currentTimeMillis())
	    		 {
	    			 npc.teleToLocation(-21600,179482,-5846);
	    			 int num = -22000;
	    			 for(L2Attackable min : _Minions)
	    			 {
	    				 min.teleToLocation(num,179482,-5846);
	    				 num = -21400;
	    			 }
	    		 }
	    	}
        }
        return super.onAdvEvent(event, npc, player);
	}

    public String onSpellFinished(L2Npc npc, L2PcInstance player, L2Skill skill)
    {
    	int npcId = npc.getNpcId();
    	if(npcId == NURSE)
    	{
    		npc.setIsCastingNow(false);
    	}
    	return super.onSpellFinished(npc, player, skill);
    }

    public String onFactionCall (L2Npc npc, L2Npc caller, L2PcInstance attacker, boolean isPet) 
    { 
        if (caller == null || npc == null || npc.isCastingNow()) 
        	return super.onFactionCall(npc, caller, attacker, isPet);
        int npcId = npc.getNpcId();
        int callerId = caller.getNpcId();
        if (caller == null || caller.isDead())
		{
			npc.setIsCastingNow(false);
			return super.onFactionCall(npc, caller, attacker, isPet);
		}
        if (callerId == GUARD && (npcId == QUEEN || npcId == ROYAL || npcId == NURSE || npcId == LARVA))
        	return null;
        if (npcId == NURSE)
        {
            if (callerId == LARVA && caller.getCurrentHp() != caller.getMaxHp())
            {
                npc.setTarget(caller);
                npc.setIsCastingNow(true);
                npc.doCast(SkillTable.getInstance().getInfo(4024,1));
                return null;
            }
            else if (callerId == QUEEN)
            {
                if (npc.getTarget() != null && npc.getTarget() instanceof L2Npc)
                {
                	if (((L2Npc) npc.getTarget()).getNpcId() == LARVA && ((L2Npc) npc.getTarget()).getCurrentHp() != ((L2Npc) npc.getTarget()).getMaxHp())
                	{
                    	return null;
                	}
                }
                npc.setTarget(caller);
                npc.setIsCastingNow(true);
                npc.doCast(SkillTable.getInstance().getInfo(4020,1));
                return null;
            }
        }
        return super.onFactionCall(npc, caller, attacker, isPet);
    }

    public String onAttack (L2Npc npc, L2PcInstance attacker, int damage, boolean isPet)
    {	
        int npcId = npc.getNpcId();
        if (npcId == NURSE)
        {
            npc.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE, null, null);
            return null;
        }
        else if (npcId == LARVA)
        {
        	_lastattack = System.currentTimeMillis();
        }
        return super.onAttack(npc, attacker, damage, isPet);
    }
        
    public String onKill (L2Npc npc, L2PcInstance killer, boolean isPet) 
    { 
        int npcId = npc.getNpcId();
        if (npcId == QUEEN)
        {
            npc.broadcastPacket(new PlaySound(1, "BS02_D", 1, npc.getObjectId(), npc.getX(), npc.getY(), npc.getZ()));
            GrandBossManager.getInstance().setBossStatus(QUEEN,DEAD);
            //time is 36hour	+/- 17hour
            long respawnTime = ((19 + Rnd.get(35) ) * 3600000);
            startQuestTimer("queen_unlock", respawnTime, null, null);
            cancelQuestTimer("action", npc, null);
            this.cancelQuestTimers("spawn_royal");
            this.cancelQuestTimers("spawn_nurse");
            this.cancelQuestTimers("checklarva");
            if(_larva != null)
            {
            	deleteLarva();
            }
            // also save the respawn time so that the info is maintained past reboots
            StatsSet info = GrandBossManager.getInstance().getStatsSet(QUEEN);
            info.set("respawn_time",System.currentTimeMillis() + respawnTime);
            GrandBossManager.getInstance().setStatsSet(QUEEN,info);
        }
        else if (GrandBossManager.getInstance().getBossStatus(QUEEN) == ALIVE)
        {
            if (npcId == ROYAL)
            {
                startQuestTimer("spawn_royal",(280+Rnd.get(40))*1000,npc,null);
            }
            else if (npcId == NURSE)
            {
            	if(((L2MinionInstance)npc).getLeader() == ((L2MonsterInstance)_larva))
            		_Minions.remove((L2Attackable)npc);
                startQuestTimer("spawn_nurse",(30+Rnd.get(90))*1000,npc,null);
            }
        }
        return super.onKill(npc,killer,isPet);
    }

    public void spawnSingleMinion(int minionId, int cord, L2MonsterInstance master)
	{	
		if(master == null || master.isDead() || master.isAlikeDead())
			return;
			
		// Get the template of the Minion to spawn
		L2NpcTemplate minionTemplate = NpcTable.getInstance().getTemplate(minionId);
		
		// Create and Init the Minion and generate its Identifier
		L2MinionInstance monster = new L2MinionInstance(IdFactory.getInstance().getNextId(), minionTemplate);
		
		// Set the Minion HP, MP and Heading
		monster.setCurrentHpMp(monster.getMaxHp(), monster.getMaxMp());
		if(master.getNpcId() != 29001)
		{
			monster.setHeading(0);
		}
		else
		{
			monster.setHeading(master.getHeading());
		}
		// Set the Minion leader to this RaidBoss
		monster.setLeader(master);
		
		//move monster to masters instance
		monster.setInstanceId(0);
		
		// Init the position of the Minion and add it in the world as a visible object
		int spawnConstant;
		int newX;
		int newY;
		int randSpawnLim = 170;
		int randPlusMin = 1;
		spawnConstant = Rnd.nextInt(randSpawnLim);
		//randomize +/-
		randPlusMin = Rnd.nextInt(2);
		if (randPlusMin == 1)
			spawnConstant *= -1;
		if(cord != 0)
		{
			newX = master.getX() + cord;	
		}
		else
		{
			newX = master.getX() + Math.round(spawnConstant);
		}
		spawnConstant = Rnd.nextInt(randSpawnLim);
		//randomize +/-
		randPlusMin = Rnd.nextInt(2);
		if (randPlusMin == 1)
			spawnConstant *= -1;
		if(cord != 0)
		{
			newY = master.getY();
		}
		else
		{
			newY = master.getY() + Math.round(spawnConstant);
		}
		if(((L2Npc)master) == _larva)
		{
			_Minions.add((L2Attackable)monster);
		}
		monster.spawnMe(newX, newY, master.getZ());
		
	}
    
    public boolean checkLarvaZone(L2Npc mob,int range, int x, int y, int z)
    {
    	if (mob == null)
			return false;
		if (range == -1)
			return true; // not limited
		
		double dx = mob.getX() - x;
		double dy = mob.getY() - y;
		
		double dz = mob.getZ() - z;
		double d = dx * dx + dy * dy + dz * dz;
			
		return d <= range * range + 2 * range * 1;	
    }
    
    public void deleteLarva()
    {
    	_larva.deleteMe();
		
		L2Spawn spawn = _larva.getSpawn();
		_larva = null;
		if (spawn != null)
		{
			spawn.stopRespawn();
			SpawnTable.getInstance().deleteSpawn(spawn, true);
		}
    }
    
    public static void main(String[] args)
    {
    	// now call the constructor (starts up the ai)
    	new QueenAnt(-1,"queen_ant","ai");
    }
}